1   /*
2    * Copyright (c) 2004-2005, University Health Network.  All rights reserved. Distributed under the BSD 
3    * license (see http://opensource.org/licenses/bsd-license.php).
4    *  
5    * ChunkBasedSemanticCache.java
6    *
7    * Created on 10-Dec-2004 at 10:58:22 AM
8    */
9   package ca.uhn.cache.impl;
10  
11  import java.text.DateFormat;
12  import java.text.ParseException;
13  import java.util.Date;
14  
15  import junitx.framework.ArrayAssert;
16  
17  import org.jmock.Mock;
18  import org.jmock.MockObjectTestCase;
19  
20  import ca.uhn.cache.CacheReasonEnum;
21  import ca.uhn.cache.IDimension;
22  import ca.uhn.cache.IParamSpace;
23  import ca.uhn.cache.IQuery;
24  import ca.uhn.cache.IQueryParam;
25  import ca.uhn.cache.VolatilityEnum;
26  import ca.uhn.cache.exception.CacheException;
27  import ca.uhn.cache.internal.IChunk;
28  import ca.uhn.cache.internal.IChunkStore;
29  
30  
31  /***
32   * Tests for cache accepting queries spanning 2 dimension.
33   * 
34   * Fixture description:
35   * 
36   * dimension1:StringSetParam = P( { A, B, C ,D, E } ), where P is the "power set".
37   * dimension2:DateRangeParam = { "Jan 01, 1800 - Dec 31, 1999", "Jan 01, 2000 - Dec 31, 2003" }
38   *
39   * chunk1 = { { A, B }, { "Jan 01, 1800 - Dec 31, 1999" } }
40   * chunk2 = { { C, D, E }, { "Jan 01, 2000 - Dec 31, 2003" } }
41   * chunk3 = { { A, B }, { "Jan 01, 2000 - Dec 31, 2003" } }
42   * chunk4 = { { C, D, E }, { "Jan 01, 1800 - Dec 31, 1999" } }
43   * 
44   * @author <a href="mailto:alexei.guevara@uhn.on.ca">Alexei Guevara</a>
45   * @version $Revision: 1.1 $ updated on $Date: 2005/01/24 22:51:46 $ by $Author: bryan_tripp $
46   */
47  public class ChunkBasedSemanticCacheTest2 extends MockObjectTestCase {
48  
49      private static DateFormat ourDateFormat = DateFormat.getDateInstance( DateFormat.MEDIUM );
50      
51      private ChunkBasedSemanticCache myChunkBasedSemanticCache;
52      
53      private Mock myParamSpaceMock;
54      private IParamSpace myParamSpace;
55      
56      private Mock myChunkStoreMock;
57      private IChunkStore myChunkStore;
58      
59      private IDimension myDimension1;
60      private IDimension myDimension2;
61  
62      private IChunk myChunk1;
63      private IChunk myChunk2;
64      private IChunk myChunk3;
65      private IChunk myChunk4;
66      
67      private IQuery myChunk1Query;    
68      private IQuery myChunk2Query;
69      private IQuery myChunk3Query;    
70      private IQuery myChunk4Query;
71      
72  
73      private StringSetParam myChunk1QueryParam1;
74      private DateRangeParam myChunk1QueryParam2;
75  
76      private StringSetParam myChunk2QueryParam1;
77      private DateRangeParam myChunk2QueryParam2;
78      
79      private StringSetParam myChunk3QueryParam1;
80      private DateRangeParam myChunk3QueryParam2;
81  
82      private StringSetParam myChunk4QueryParam1;
83      private DateRangeParam myChunk4QueryParam2;
84      
85  
86      /*
87       * @see TestCase#setUp()
88       */
89      protected void setUp() throws Exception {
90          super.setUp();
91          
92          myChunkBasedSemanticCache = new ChunkBasedSemanticCache();
93          
94          myParamSpaceMock = new Mock( IParamSpace.class, "myParamSpace" );
95          myParamSpace = (IParamSpace) myParamSpaceMock.proxy();
96          
97          myChunkStoreMock = new Mock( IChunkStore.class, "myChunkStore" );
98          myChunkStore = (IChunkStore) myChunkStoreMock.proxy();
99          
100         myChunkBasedSemanticCache.setParamSpace( myParamSpace );
101         myChunkBasedSemanticCache.setChunkStore( myChunkStore );
102         
103         myDimension1 = new Dimension( "P( A, B, C, D, E )", new Class[] { StringSetParam.class } );
104         myDimension2 = new Dimension( "01/Jan/1800 - 31/Dec/2003", new Class[] { DateRangeParam.class } );
105 
106         //chunk1
107         myChunk1QueryParam1 = new StringSetParam( myDimension1, new String[] { "A", "B" } );
108         myChunk1QueryParam2 = 
109             new DateRangeParam( 
110                     myDimension2, 
111                     ourDateFormat.parse( "Jan 01, 1800" ), 
112                     ourDateFormat.parse( "Dec 31, 1999" ) );
113         myChunk1Query = new Query();
114         myChunk1Query.addParameter( myChunk1QueryParam1 );
115         myChunk1Query.addParameter( myChunk1QueryParam2 );
116         myChunk1 = 
117             new Chunk( "chunkId1", VolatilityEnum.STABLE, 
118                        new Date(), new Date(), new Date(), 
119                        new CacheReasonEnum[] { CacheReasonEnum.PRE_FETCH }, 
120                        myChunk1Query );
121         
122         //chunk2
123         myChunk2QueryParam1 = new StringSetParam( myDimension1, new String[] { "C", "D", "E" } );
124         myChunk2QueryParam2 = 
125             new DateRangeParam( 
126                     myDimension2, 
127                     ourDateFormat.parse( "Jan 01, 2000" ), 
128                     ourDateFormat.parse( "Dec 31, 2003" ) );
129         myChunk2Query = new Query();
130         myChunk2Query.addParameter( myChunk2QueryParam1 );
131         myChunk2Query.addParameter( myChunk2QueryParam2 );
132         myChunk2 = 
133             new Chunk( "chunkId2", VolatilityEnum.STABLE, 
134                        new Date(), new Date(), new Date(), 
135                        new CacheReasonEnum[] { CacheReasonEnum.PRE_FETCH }, 
136                        myChunk2Query );
137 
138         //chunk3
139         myChunk3QueryParam1 = new StringSetParam( myDimension1, new String[] { "A", "B" } );
140         myChunk3QueryParam2 = 
141             new DateRangeParam( 
142                     myDimension2, 
143                     ourDateFormat.parse( "Jan 01, 2000" ), 
144                     ourDateFormat.parse( "Dec 31, 2003" ) );
145         myChunk3Query = new Query();
146         myChunk3Query.addParameter( myChunk3QueryParam1 );
147         myChunk3Query.addParameter( myChunk3QueryParam2 );
148         myChunk3 = 
149             new Chunk( "chunkId3", VolatilityEnum.STABLE, 
150                        new Date(), new Date(), new Date(), 
151                        new CacheReasonEnum[] { CacheReasonEnum.PRE_FETCH }, 
152                        myChunk3Query );
153         
154         //chunk4
155         myChunk4QueryParam1 = new StringSetParam( myDimension1, new String[] { "C", "D", "E" } );
156         myChunk4QueryParam2 = 
157             new DateRangeParam( 
158                     myDimension2, 
159                     ourDateFormat.parse( "Jan 01, 1800" ), 
160                     ourDateFormat.parse( "Dec 31, 1999" ) );
161         myChunk4Query = new Query();
162         myChunk4Query.addParameter( myChunk4QueryParam1 );
163         myChunk4Query.addParameter( myChunk4QueryParam2 );
164         myChunk4 = 
165             new Chunk( "chunkId4", VolatilityEnum.STABLE, 
166                        new Date(), new Date(), new Date(), 
167                        new CacheReasonEnum[] { CacheReasonEnum.PRE_FETCH }, 
168                        myChunk4Query );
169 
170         
171     }
172 
173     /*
174      * @see TestCase#tearDown()
175      */
176     protected void tearDown() throws Exception {
177         super.tearDown();
178     }
179 
180     /***
181      * @throws CacheException ...
182      */
183     public void testRemainder1_1() throws CacheException {
184         
185         IQuery query = new Query();
186         
187         IQuery[] expectedReminder = new IQuery[] {};
188         
189         IQuery[] actualRemider = myChunkBasedSemanticCache.remainder( query , 0 );
190         
191         ArrayAssert.assertEquals( expectedReminder, actualRemider );
192     }
193     
194     /***
195      * - empty chunk store
196      * 
197      * @throws CacheException ...
198      * @throws ParseException ...
199      */
200     public void testRemainder2_1() throws CacheException, ParseException {
201         //empty chunk store
202         myChunkStoreMock.expects( once() ).method( "get" ).with( eq( myChunk1Query ) ).will( returnValue( null ) );
203 
204         //original query (spans chunk 1)
205         StringSetParam queryParam1 = new StringSetParam( myDimension1, new String[] { "A" } );        
206         DateRangeParam queryParam2 = 
207             new DateRangeParam( 
208                     myDimension2, 
209                     ourDateFormat.parse( "Jan 01, 1900" ), 
210                     ourDateFormat.parse( "Dec 31, 1901" ) );
211         
212         IQuery query = new Query();
213         query.addParameter( queryParam1 );
214         query.addParameter( queryParam2 );
215         
216         //param within chunk1
217         myParamSpaceMock.expects( once() )
218             .method( "chunk" )
219             .with( eq( queryParam1 ) ) 
220             .will( returnValue( new IQueryParam[] { myChunk1QueryParam1 } ) );
221         
222         myParamSpaceMock.expects( once() )
223             .method( "chunk" )
224             .with( eq( queryParam2 ) ) 
225             .will( returnValue( new IQueryParam[] { myChunk1QueryParam2 } ) );
226         
227         //expected remider query
228         IQuery[] expectedReminder = new IQuery[] { myChunk1Query };
229         
230         //actual query
231         IQuery[] actualRemider = myChunkBasedSemanticCache.remainder( query , 0 );
232         
233         ArrayAssert.assertEquals( expectedReminder, actualRemider );
234     }
235     
236     /***
237      * - empty chunk store
238      * 
239      * @throws CacheException ...
240      * @throws ParseException ...
241      */
242     public void testRemainder2_2() throws CacheException, ParseException {
243         //empty chunk store
244         myChunkStoreMock.expects( once() ).method( "get" ).with( eq( myChunk2Query ) ).will( returnValue( null ) );
245         
246         //original query (spans chunk 2)
247         StringSetParam queryParam1 = new StringSetParam( myDimension1, new String[] { "D" } );
248         DateRangeParam queryParam2 = 
249             new DateRangeParam( 
250                     myDimension2, 
251                     ourDateFormat.parse( "Jan 01, 2001" ), 
252                     ourDateFormat.parse( "Dec 31, 2002" ) );
253         
254         IQuery query = new Query();
255         query.addParameter( queryParam1 );
256         query.addParameter( queryParam2 );
257         
258         //param within chunk2
259         myParamSpaceMock.expects( once() )
260             .method( "chunk" )
261             .with( eq( queryParam1 ) )
262             .will( returnValue( new IQueryParam[] { myChunk2QueryParam1 } ) );
263         
264         myParamSpaceMock.expects( once() )
265             .method( "chunk" )
266             .with( eq( queryParam2 ) )
267             .will( returnValue( new IQueryParam[] { myChunk2QueryParam2 } ) );
268         
269         IQuery[] expectedReminder = new IQuery[] { myChunk2Query };
270         
271         //actual query
272         IQuery[] actualRemider = myChunkBasedSemanticCache.remainder( query , 0 );
273         
274         ArrayAssert.assertEquals( expectedReminder, actualRemider );
275     }
276 
277     /***
278      * - empty chunk store
279      * 
280      * @throws CacheException ...
281      * @throws ParseException ...
282      */
283     public void testRemainder2_3() throws CacheException, ParseException {
284         //empty chunk store
285         myChunkStoreMock.expects( once() ).method( "get" ).with( eq( myChunk1Query ) ).will( returnValue( null ) );
286         myChunkStoreMock.expects( once() ).method( "get" ).with( eq( myChunk2Query ) ).will( returnValue( null ) );
287         myChunkStoreMock.expects( once() ).method( "get" ).with( eq( myChunk3Query ) ).will( returnValue( null ) );
288         myChunkStoreMock.expects( once() ).method( "get" ).with( eq( myChunk4Query ) ).will( returnValue( null ) );
289         
290         //original query (spans chunk 1, 2, 3 and 4)
291         StringSetParam queryParam1 = new StringSetParam( myDimension1, new String[] { "A", "D" } );
292         DateRangeParam queryParam2 = 
293             new DateRangeParam( 
294                     myDimension2, 
295                     ourDateFormat.parse( "Jan 01, 1850" ), 
296                     ourDateFormat.parse( "Dec 31, 2003" ) );
297         
298         IQuery query = new Query();
299         query.addParameter( queryParam1 );
300         query.addParameter( queryParam2 );
301         
302         //param within chunk1 and chunk2
303         myParamSpaceMock.expects( once() )
304             .method( "chunk" )
305             .with( eq( queryParam1 ) ) 
306             .will( returnValue( new IQueryParam[] { myChunk1QueryParam1, myChunk2QueryParam1 } ) );
307         
308         myParamSpaceMock.expects( once() )
309             .method( "chunk" )
310             .with( eq( queryParam2 ) ) 
311             .will( returnValue( new IQueryParam[] { myChunk1QueryParam2, myChunk2QueryParam2 } ) );
312         
313         IQuery[] expectedReminder = new IQuery[] { myChunk1Query, myChunk2Query, myChunk3Query, myChunk4Query };
314         
315         //actual query
316         IQuery[] actualRemider = myChunkBasedSemanticCache.remainder( query , 0 );
317         
318         ArrayAssert.assertEquivalenceArrays( expectedReminder, actualRemider );
319     }
320     
321     /***
322      * - chunk1 in chunk store
323      * 
324      * @throws CacheException ...
325      * @throws ParseException ...
326      */
327     public void testRemainder3_1() throws CacheException, ParseException {
328         //empty chunk store
329         myChunkStoreMock.expects( once() ).method( "get" ).with( eq( myChunk1Query ) ).will( returnValue( myChunk1 ) );
330 
331         //original query (spans chunk 1)
332         StringSetParam queryParam1 = new StringSetParam( myDimension1, new String[] { "A" } );        
333         DateRangeParam queryParam2 = 
334             new DateRangeParam( 
335                     myDimension2, 
336                     ourDateFormat.parse( "Jan 01, 1800" ),  
337                     ourDateFormat.parse( "Dec 31, 1999" ) );
338         
339         IQuery query = new Query();
340         query.addParameter( queryParam1 );
341         query.addParameter( queryParam2 );
342         
343         //param within chunk1
344         myParamSpaceMock.expects( once() )
345             .method( "chunk" )
346             .with( eq( queryParam1 ) ) 
347             .will( returnValue( new IQueryParam[] { myChunk1QueryParam1 } ) );
348         
349         myParamSpaceMock.expects( once() )
350             .method( "chunk" )
351             .with( eq( queryParam2 ) ) 
352             .will( returnValue( new IQueryParam[] { myChunk1QueryParam2 } ) );
353         
354         //expected remider query
355         IQuery[] expectedReminder = new IQuery[] {};
356         
357         //actual query
358         IQuery[] actualRemider = myChunkBasedSemanticCache.remainder( query , 0 );
359         
360         ArrayAssert.assertEquals( expectedReminder, actualRemider );
361     }
362     
363     /***
364      * - chunk2 in chunk store
365      * 
366      * @throws CacheException ...
367      * @throws ParseException ...
368      */
369     public void testRemainder3_2() throws CacheException, ParseException {
370         //empty chunk store
371         myChunkStoreMock.expects( once() ).method( "get" ).with( eq( myChunk2Query ) ).will( returnValue( myChunk2 ) );
372         
373         //original query (spans chunk 2)
374         StringSetParam queryParam1 = new StringSetParam( myDimension1, new String[] { "D" } );
375         DateRangeParam queryParam2 = 
376             new DateRangeParam( 
377                     myDimension2, 
378                     ourDateFormat.parse( "Jan 01, 2001" ), 
379                     ourDateFormat.parse( "Dec 31, 2002" ) );
380         
381         IQuery query = new Query();
382         query.addParameter( queryParam1 );
383         query.addParameter( queryParam2 );
384         
385         myParamSpaceMock.expects( once() )
386             .method( "chunk" )
387             .with( eq( queryParam1 ) )
388             .will( returnValue( new IQueryParam[] { myChunk2QueryParam1 } ) );
389         
390         myParamSpaceMock.expects( once() )
391             .method( "chunk" )
392             .with( eq( queryParam2 ) )
393             .will( returnValue( new IQueryParam[] { myChunk2QueryParam2 } ) );
394         
395         IQuery[] expectedReminder = new IQuery[] {};
396         
397         //actual query
398         IQuery[] actualRemider = myChunkBasedSemanticCache.remainder( query , 0 );
399         
400         ArrayAssert.assertEquals( expectedReminder, actualRemider );
401     }
402 
403     /***
404      * - chunk3 in chunk store
405      * 
406      * @throws CacheException ...
407      * @throws ParseException ...
408      */
409     public void testRemainder3_3() throws CacheException, ParseException {
410         //empty chunk store
411         myChunkStoreMock.expects( once() ).method( "get" ).with( eq( myChunk3Query ) ).will( returnValue( myChunk3 ) );
412         
413         //original query (spans chunk 3)
414         StringSetParam queryParam1 = new StringSetParam( myDimension1, new String[] { "A" } );
415         DateRangeParam queryParam2 = 
416             new DateRangeParam( 
417                     myDimension2, 
418                     ourDateFormat.parse( "Jan 01, 2001" ), 
419                     ourDateFormat.parse( "Dec 31, 2002" ) );
420         
421         IQuery query = new Query();
422         query.addParameter( queryParam1 );
423         query.addParameter( queryParam2 );
424         
425         //param within chunk1 and chunk2
426         myParamSpaceMock.expects( once() )
427             .method( "chunk" )
428             .with( eq( queryParam1 ) ) 
429             .will( returnValue( new IQueryParam[] { myChunk3QueryParam1 } ) );
430         
431         myParamSpaceMock.expects( once() )
432             .method( "chunk" )
433             .with( eq( queryParam2 ) ) 
434             .will( returnValue( new IQueryParam[] { myChunk3QueryParam2 } ) );
435         
436         IQuery[] expectedReminder = new IQuery[] {};
437         
438         //actual query
439         IQuery[] actualRemider = myChunkBasedSemanticCache.remainder( query , 0 );
440         
441         ArrayAssert.assertEquivalenceArrays( expectedReminder, actualRemider );
442     }
443     
444     /***
445      * - chunk4 in chunk store
446      * 
447      * @throws CacheException ...
448      * @throws ParseException ...
449      */
450     public void testRemainder3_4() throws CacheException, ParseException {
451         //empty chunk store
452         myChunkStoreMock.expects( once() ).method( "get" ).with( eq( myChunk4Query ) ).will( returnValue( myChunk4 ) );
453         
454         //original query (spans chunk 3)
455         StringSetParam queryParam1 = new StringSetParam( myDimension1, new String[] { "D" } );
456         DateRangeParam queryParam2 = 
457             new DateRangeParam( 
458                     myDimension2, 
459                     ourDateFormat.parse( "Jan 01, 1800" ),  
460                     ourDateFormat.parse( "Dec 31, 1999" ) );
461         
462         IQuery query = new Query();
463         query.addParameter( queryParam1 );
464         query.addParameter( queryParam2 );
465         
466         //param within chunk4
467         myParamSpaceMock.expects( once() )
468             .method( "chunk" )
469             .with( eq( queryParam1 ) ) 
470             .will( returnValue( new IQueryParam[] { myChunk4QueryParam1 } ) );
471         
472         myParamSpaceMock.expects( once() )
473             .method( "chunk" )
474             .with( eq( queryParam2 ) ) 
475             .will( returnValue( new IQueryParam[] { myChunk4QueryParam2 } ) );
476         
477         IQuery[] expectedReminder = new IQuery[] {};
478         
479         //actual query
480         IQuery[] actualRemider = myChunkBasedSemanticCache.remainder( query , 0 );
481         
482         ArrayAssert.assertEquivalenceArrays( expectedReminder, actualRemider );
483     }
484     
485     /***
486      * - chunk1 in chunk store
487      * - chunk4 not in chunk store
488      * 
489      * @throws CacheException ...
490      * @throws ParseException ...
491      */
492     public void testRemainder3_5() throws CacheException, ParseException {
493         //empty chunk store
494         myChunkStoreMock.expects( once() ).method( "get" ).with( eq( myChunk1Query ) ).will( returnValue( myChunk1 ) );
495         myChunkStoreMock.expects( once() ).method( "get" ).with( eq( myChunk4Query ) ).will( returnValue( null ) );
496 
497         //original query (spans chunk 1 and 4)
498         StringSetParam queryParam1 = new StringSetParam( myDimension1, new String[] { "A", "D" } );        
499         DateRangeParam queryParam2 = 
500             new DateRangeParam( 
501                     myDimension2, 
502                     ourDateFormat.parse( "Jan 01, 1800" ),  
503                     ourDateFormat.parse( "Dec 31, 1999" ) );
504         
505         IQuery query = new Query();
506         query.addParameter( queryParam1 );
507         query.addParameter( queryParam2 );
508         
509         //param within chunk1
510         myParamSpaceMock.expects( once() )
511             .method( "chunk" )
512             .with( eq( queryParam1 ) ) 
513             .will( returnValue( new IQueryParam[] { myChunk1QueryParam1, myChunk4QueryParam1 } ) );
514         
515         myParamSpaceMock.expects( once() )
516             .method( "chunk" )
517             .with( eq( queryParam2 ) ) 
518             .will( returnValue( new IQueryParam[] { myChunk1QueryParam2 } ) );
519         
520         //expected remider query
521         IQuery[] expectedReminder = new IQuery[] { myChunk4Query };
522         
523         //actual query
524         IQuery[] actualRemider = myChunkBasedSemanticCache.remainder( query , 0 );
525         
526         ArrayAssert.assertEquals( expectedReminder, actualRemider );
527     }
528     
529     
530 }
531